package com.yjzx.util.service.aop.log;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.yjzx.util.common.util.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;

/**
 * @author yjzx
 * @date 2023/11/3
 * @description 日志打印过滤器
 */
public class LogFilter extends OncePerRequestFilter implements Ordered {
    private final Logger log = LoggerFactory.getLogger(getClass());
    private final int order = Ordered.LOWEST_PRECEDENCE - 8;
    public static final String SPLIT_STRING_M = "=";
    public static final String SPLIT_STRING_DOT = ", ";
    public static final String SPACE = "[\r|\n|\t| ]";

    private static final String URL = "[访问地址] :";
    private static final String PARAM = "[请求参数] :";
    private static final String RETURN = "[返回数据] :";
    private static final String TIME = "[执行时间] :";

    @Override
    public int getOrder() {
        return order;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        ContentCachingRequestWrapper wrapperRequest = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper(response);
        long start = System.currentTimeMillis();
        MDC.put("clientIp", IpUtil.getIpAddress(request));
        filterChain.doFilter(wrapperRequest, wrapperResponse);
        //需执行完成方法，缓存中查询请求体
        requestLog(request, wrapperRequest);
        responseLog(wrapperResponse, start);
        wrapperResponse.copyBodyToResponse();
        MDC.remove("clientIp");
        MDC.remove("name");
    }

    private void requestLog(HttpServletRequest request, ContentCachingRequestWrapper wrapperRequest) {
        String uri = request.getRequestURI();
        String urlParams = getRequestParams(request);
        String requestBodyStr = getRequestBody(wrapperRequest);
        String param = (StringUtils.isNotBlank(urlParams) ? "urlParams:[" + urlParams + "]" : "") +
                (StringUtils.isNotBlank(requestBodyStr) ? "requestBody:" + requestBodyStr : "");
        log.info(URL + uri);
        log.info(PARAM + param);
    }

    private void responseLog(ContentCachingResponseWrapper wrapperResponse, long start) {
        String responseBodyStr = getResponseBody(wrapperResponse);
        log.info(RETURN + responseBodyStr);
        log.info(TIME + (System.currentTimeMillis() - start) + "ms");
    }

    /**
     * 获取请求地址上的参数
     *
     * @param request
     * @return
     */
    public static String getRequestParams(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        Enumeration<String> enu = request.getParameterNames();
        //获取请求参数
        while (enu.hasMoreElements()) {
            String name = enu.nextElement();
            String param = request.getParameter(name);
            if (StringUtils.isNotBlank(param)) {
                sb.append(name).append(SPLIT_STRING_M).append(param);
                if (enu.hasMoreElements()) {
                    sb.append(SPLIT_STRING_DOT);
                }
            }
        }
        return sb.toString();
    }

    /**
     * 打印请求体参数
     *
     * @param request
     */
    private String getRequestBody(ContentCachingRequestWrapper request) {
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                String payload;
                try {
                    payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                    payload = "[unknown]";
                }
                return payload.replaceAll(SPACE, "");
            }
        }
        return "";
    }

    /**
     * 打印返回参数
     *
     * @param response
     */
    private String getResponseBody(ContentCachingResponseWrapper response) {
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response,
                ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                String payload;
                try {
                    payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                    payload = "[unknown]";
                }
                return payload.replaceAll(SPACE, "");
            }
        }
        return "";
    }
}
